﻿namespace GoodAdmin.System;

public class SysOrgService : DbRepository<SysOrg>, ISysOrgService, ITransient
{
    private readonly IRedisCacheManager _redisManager;

    public SysOrgService(IRedisCacheManager redisManager)
    {
        _redisManager = redisManager;        
    }
    /// <inheritdoc/>
    public async Task AddOrg(OrgAddInput input)
    {
        await CheckInput(input,CommonConst.ACTION_INSERT);
        var parentOrg = await GetOrgDetail(input.ParentId);
        
        input.LongName = parentOrg != null? $"{parentOrg.LongName}{input.OrgName}" : input.OrgName;
        
        if(await InsertAsync(input))
        {
            RemoveOrgCache();
            //新增组织时，只会影响上级
            await RemoveDataScopeCache(input.ParentId);
        }
        
    }
    /// <inheritdoc/>
    public async Task DeleteOrg(BaseIdInput input)
    {
        //包含下级组织不能删除
        if (await IsAnyAsync(o => o.ParentId == input.Id))
        {
            throw Oops.Bah(OrgErrorCode.O003);
        }
        //包含用户不能删除
        if (await Context.Queryable<SysUser>().AnyAsync(u => u.OrgId == input.Id))
        {
            throw Oops.Bah(OrgErrorCode.O004);
        }
                
        if(await DeleteAsync(o => o.Id == input.Id))
        {
            RemoveOrgCache();
            await RemoveDataScopeCache(input.Id);
        }
        
    }

    /// <inheritdoc/>
    public async Task<SysOrg> GetOrgDetail(long OrgId)
    {
        var orgList = await GetOrgList();
        return orgList.FirstOrDefault(o => o.Id == OrgId);
    }
    /// <inheritdoc/>
    public async Task<List<SysOrg>> GetOrgList()
    {
        var key = CacheConst.SysOrg;

        var orgList = _redisManager.Get<List<SysOrg>>(key);
        if (orgList == null)
        {
            orgList = await GetListAsync();
            _redisManager.Set(key, orgList);
        }
        return orgList;
    }
    /// <inheritdoc/>
    public async Task<List<SysOrg>> GetOrgTree(List<long> dataScope=null)
    {        
        var orgList = await GetOrgList();
        if (dataScope!=null)
        {
            orgList =orgList.Where(it=> dataScope.Contains(it.Id)).ToList();
        }
        return ConstructOrgTree(orgList);
    }

    /// <inheritdoc/>
    public async Task<SqlSugarPagedList<SysOrg>> GetOrgPageList(OrgPageInput input)
    {        
        return await Context.Queryable<SysOrg>()
            .WhereIF(!string.IsNullOrWhiteSpace(input.Category),o=>o.Category==input.Category)
            .WhereIF(input.ParentId>0,o=>o.ParentId==input.ParentId)
            .WhereIF(input.DataScope!=null,o=>input.DataScope.Contains(o.Id))
            .WhereIF(!string.IsNullOrWhiteSpace(input.OrgName),o=>o.OrgName.Contains(input.OrgName))
            .OrderByIF(!string.IsNullOrWhiteSpace(input.SortField),o=> $"{input.SortField} {input.SortOrder}")
            .OrderBy(o=>o.SortCode)
            .ToPagedListAsync(input.PageIndex, input.PageSize);
    }

    /// <inheritdoc/>
    public async Task UpdateOrg(OrgUpdateInput input)
    {
        var sysOrg = await GetOrgDetail(input.Id);  
        await CheckInput(input, CommonConst.ACTION_UPDATE);

        var parentOrg = await GetOrgDetail(input.ParentId);
        input.LongName = parentOrg != null ? $"{parentOrg.LongName}{input.OrgName}" : input.OrgName;
        if (await UpdateAsync(input))
        {
            RemoveOrgCache();
            await RemoveUserCache(input.Id);

            //更新前后上级组织如果有变化，需删除数据范围
            if (input.ParentId != sysOrg.ParentId)
            {
                //删除之前上级部门的
                await RemoveDataScopeCache(sysOrg.ParentId);
                //删除更新后的上级部门的
                await RemoveDataScopeCache(input.ParentId);
            }
        }
        
    }

    /// <inheritdoc/>
    public async Task<bool> IsOrgExist(long OrgId) 
    {
        var orgList = await GetOrgList();
        return orgList.Any(o => o.Id == OrgId);
    }

    /// <inheritdoc/>
    public async Task<List<SysOrg>> GetOrgChildrenList(long OrgId, bool isContainSelf = true)
    {
        var childList = await GetChildListAsync(o => o.ParentId, OrgId, isContainSelf);
        return childList;
    }

    /// <inheritdoc/>
    public async Task<List<long>> GetOrgChildrenIdList(long OrgId, bool isContainSelf = true)
    {
        var orgList = await GetOrgList();
        var curOrg = orgList.Where(o => o.Id == OrgId).FirstOrDefault();
        List<long> result = new();
        if (curOrg == null) 
            return result;

        Queue<SysOrg> queue = new();
        queue.Enqueue(curOrg);
        while (queue.Count > 0)
        {
            var org = queue.Dequeue();
            var childs = orgList.Where(o => o.ParentId == org.Id).ToList();
            childs?.ForEach(o =>
            {
                queue.Enqueue(o);
                result.Add(o.Id);
            });
        }
        if (isContainSelf)
        {
            result.Add(OrgId);
        }
        return result;
    }
   
    /// <inheritdoc/>
    public async Task<List<long>> GetOrgParentIdList(long orgId, bool isContainSelf = true)
    {
        var orgList = await GetOrgList();
        var curOrg = orgList.Where(o => o.Id == orgId).FirstOrDefault();
        List<long> result = new();
        if (curOrg == null) 
            return result;

        Queue<SysOrg> queue = new();
        queue.Enqueue(curOrg);
        while (queue.Count > 0)
        {
            var org = queue.Dequeue();
            var parent= orgList.Where(o => o.Id == org.ParentId).FirstOrDefault();
            if(parent != null) 
            { 
                result.Add(parent.Id);
                queue.Enqueue(parent); 
            }            
        }
        if(isContainSelf)
        {
            result.Add(orgId);
        }
        return result;
    }

    /// <inheritdoc/>
    public List<SysOrg> ConstructOrgTree(List<SysOrg> orgList)
    {
        //数据范围中可能不包含顶级组织        
        var orgIdList = orgList.Select(o => o.Id).ToList();
        //找出当前列表中的最上级
        var topOrgs = orgList.Where(o => !orgIdList.Contains(o.ParentId)).ToList();
        topOrgs.ForEach(o => {
            o.Children = ConstructOrgTree(orgList, o.Id);
        });        
        return topOrgs;
    }


    #region 私有方法
    
    /// <summary>
    /// 检查输入数据是否合法
    /// </summary>
    /// <param name="sysOrg"></param>
    /// <param name="action"></param>
    /// <returns></returns>
    private async Task CheckInput(SysOrg sysOrg,string action)
    {                
        var orgList = await GetOrgList();
        //判断上级组织是否存在,parentId=0表示最上级组织
        if (sysOrg.ParentId>0 && !orgList.Any(o=>o.Id==sysOrg.ParentId))
        {
            throw Oops.Bah(OrgErrorCode.O006);
        }
        //判断同一层级中是否已有同名组织
        if (orgList.Any(o => o.ParentId == sysOrg.ParentId && o.OrgName == sysOrg.OrgName && o.Id != sysOrg.Id))
            throw Oops.Bah(OrgErrorCode.O002);
        
        //修改时需要判断修改后的父级组织是否在自己的下级组织列表里
        if (action== CommonConst.ACTION_UPDATE)
        {
            if (sysOrg.Id == sysOrg.ParentId)
                throw Oops.Bah(OrgErrorCode.O001);
            if(!orgList.Any(it=>it.Id== sysOrg.Id))
            {
                throw Oops.Bah(OrgErrorCode.O008);
            }
            var result = new List<long>();
            var child = GetChild(orgList, result, new List<long> { sysOrg.Id});
            if (child.Any(id => id == sysOrg.ParentId))
            {
                throw Oops.Bah(OrgErrorCode.O005);
            }
        }        
    }

    /// <summary>
    /// 构造组织树形列表
    /// </summary>
    /// <param name="orgList"></param>
    /// <param name="ParentId"></param>
    /// <returns></returns>
    private List<SysOrg> ConstructOrgTree(List<SysOrg> orgList, long ParentId)
    {
        var orgs = orgList.Where(it => it.ParentId == ParentId).ToList();
        if (orgs.Count == 0) return orgs;
        foreach (var org in orgs)
        {
            org.Children = ConstructOrgTree(orgList, org.Id);
        }
        return orgs;
    }
    /// <summary>
    /// 使用递归查找下级，不包含自己
    /// </summary>
    /// <param name="result"></param>
    /// <param name="orgIds"></param>
    /// <returns></returns>
    private List<long> GetChild(List<SysOrg> orgList, List<long> result, List<long> orgIds)
    {
        if (orgIds.Count == 0) return result;//如果没有下级数据，那么直接返回result结果
        var orgChilds = orgList.Where(o => orgIds.Contains(o.ParentId)).Select(o => o.Id).ToList();
        result.AddRange(orgChilds);
        return GetChild(orgList, result, orgChilds);
    }

    /// <summary>
    /// 移除部门信息缓存
    /// </summary>
    private void RemoveOrgCache()
    {
        _redisManager.Remove(CacheConst.SysOrg);
    }

    /// <summary>
    /// 移除当前部门及上级所包含用户的数据范围
    /// </summary>
    /// <param name="orgId"></param>
    /// <returns></returns>
    private async Task RemoveDataScopeCache(long orgId)
    {
        var orgList = new List<long>();
        orgList.AddRange(await GetOrgParentIdList(orgId));
        var userIdList = await GetFieldListAsync<SysUser,string>(u=>orgList.Contains(u.Id),u=>u.Id.ToString());
        //移除角色对应的用户所拥有的数据范围缓存
        foreach (var userId in userIdList)
        {
            var key = CacheConst.DataScope + userId;
            _redisManager.Remove(key);
        }
    }

    /// <summary>
    /// 移除当前部门所包含用户信息缓存
    /// </summary>
    /// <param name="orgId"></param>
    /// <returns></returns>
    private async Task RemoveUserCache(long orgId)
    {
        //var userList = await _userService.GetUserByOrgId( orgId);
        var userIdList = await GetFieldListAsync<SysUser, string>(u => u.OrgId == orgId, u => u.Id.ToString());
        if (userIdList.Count > 0)
            _redisManager.HashDel<SysUser>(CacheConst.SysUser, userIdList.ToArray());
    }
    #endregion
}